package org.mindrive.system.service.system;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.extern.slf4j.Slf4j;
import net.sourceforge.pinyin4j.format.HanyuPinyinCaseType;
import net.sourceforge.pinyin4j.format.HanyuPinyinOutputFormat;
import net.sourceforge.pinyin4j.format.HanyuPinyinToneType;
import net.sourceforge.pinyin4j.format.HanyuPinyinVCharType;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.mindrive.system.collection.system.PermissionEntity;
import org.mindrive.system.collection.system.RoleEntity;
import org.mindrive.system.collection.system.UserEntity;
import org.mindrive.system.collection.system.UserRoleEntity;
import org.mindrive.system.core.MindriveException;
import org.mindrive.system.parameter.system.PasswordParameter;
import org.mindrive.system.parameter.system.UserParameter;
import org.mindrive.system.parameter.system.UsersSearchParameter;
import org.mindrive.system.service.BaseService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.Resource;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.util.*;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

@Service
@Slf4j
public class UserService extends BaseService {

    @Value("classpath:data/avatar.png")
    private Resource avatarResource;

    @Autowired
    private AuthenticationManager authenticationManager;

    public UserEntity register(UserParameter parameter) {
        QueryWrapper<UserEntity> query = new QueryWrapper<UserEntity>();
        query.eq("user_id", parameter.getUserId());
        int count = userDao.count(query);
        if (count != 0) {
            throw new MindriveException("用户ID已经存在");
        }

        QueryWrapper<UserEntity> query2 = new QueryWrapper<UserEntity>();
        query2.eq("user_name", parameter.getUserName());
        count = userDao.count(query2);
        if (count != 0) {
            throw new MindriveException("姓名已经存在");
        }
//        if (parameter.getPassword() == null || "".equals(parameter.getPassword().trim())) {
//            throw new MindriveException("密码不能为空");
//        }

        BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
//        String pwd = encoder.encode(parameter.getPassword());
        UserEntity user = new UserEntity();
        user.setUserId(parameter.getUserId());
        user.setUserName(parameter.getUserName());
//        user.setPassword(pwd);
//        user.setEmail(parameter.getEmail());
//        user.setPhoneNumber(parameter.getPhoneNumber());
        user.setStatus(USER_STATUS_NORMAL);
        user.setCurrentWorkspaceId("");
        user.setCreatedAt(new Date());
        user.setCreator("");
        userDao.save(user);

        List<RoleEntity> systemUserRoles = roleDao.list(
                new QueryWrapper<RoleEntity>().eq("code", ROLE_CODE_SYSTEM_USER));
        for (RoleEntity role : systemUserRoles) {
            UserRoleEntity item = new UserRoleEntity();
            item.setRoleId(role.getId());
            item.setUserId(user.getId());
            item.setWorkspaceId("");
            userRoleDao.save(item);
        }


        return user;

    }

    public UserEntity getUserByUserName(String userName){
        final UserEntity user = userDao.getByUserId(userName);
        if (user.getStatus().equals(USER_STATUS_REMOVED)){
            throw new MindriveException("当前用户已停用,无法登陆");
        }
        return user;
    }

    public UserEntity create(UserParameter parameter) {
        UserEntity loginUser = getLoginUser();
        if (convertToPinyin(parameter.getUserId())){
            throw new MindriveException("用户ID不可带有中文,请重新输入");
        }
        QueryWrapper<UserEntity> query = new QueryWrapper<UserEntity>();
        query.eq("user_id", parameter.getUserId());
        int count = userDao.count(query);
        if (count != 0) {
            throw new MindriveException("用户ID已经存在");
        }
        //校验用户手机号
//        if ((parameter.getPhoneNumber()!= null) && (!parameter.getPhoneNumber().isEmpty())) {
//            final boolean matches = Pattern.matches("^1[3-9]\\d{9}$", parameter.getPhoneNumber());
//            if (!matches){
//                throw new MindriveException("手机号格式错误");
//            }
//        }
        QueryWrapper<UserEntity> query2 = new QueryWrapper<UserEntity>();
        query2.eq("user_name", parameter.getUserName());
        count = userDao.count(query2);
        if (count != 0) {
            throw new MindriveException("姓名已经存在");
        }

        BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
        String pwd = encoder.encode(parameter.getUserId() + PASSWORD_INIT);
        UserEntity user = new UserEntity();
        user.setUserId(parameter.getUserId());
        user.setUserName(parameter.getUserName());
        user.setPassword(pwd);
        user.setIdNumber(parameter.getIdNumber());
        user.setBankCardNumber(parameter.getBankCardNumber());
//        user.setEmail(parameter.getEmail());
//        user.setPhoneNumber(parameter.getPhoneNumber());
        user.setStatus(USER_STATUS_NORMAL);
        user.setFillOutStatus(NO_STATUS);
        user.setCurrentWorkspaceId("");
        user.setCreatedAt(new Date());
        user.setCreator(loginUser.getUserId());
        userDao.save(user);

        InputStream avatarInputStream = null;
        try {
            avatarInputStream = this.avatarResource.getInputStream();
            File useAvatar = new File(destPath + File.separator + USER_AVATAR + File.separator + user.getId());
            FileUtils.copyInputStreamToFile(avatarInputStream, useAvatar);
            UserEntity update = new UserEntity();
            update.setId(user.getId());
            update.setAvatar(user.getId());
            userDao.updateById(update);

        } catch (IOException e) {
            log.error("保存头像失败", e);
        } finally {
            if (avatarInputStream != null) {
                try {
                    avatarInputStream.close();
                } catch (IOException e) {
                    avatarInputStream = null;
                }
            }
        }

        return user;
    }

    public void modify(String id, UserParameter parameter) {
        UserEntity loginUser = getLoginUser();

        QueryWrapper<UserEntity> query = new QueryWrapper<UserEntity>();
        query.eq("user_name", parameter.getUserId()).ne("id", id);
        int count = userDao.count(query);
        if (count != 0) {
            throw new MindriveException("姓名已经存在");
        }
        //校验用户手机号
//        String regex = "^1[3,4,5,6,7,8,9][0-9]{9}$";
//        if(!parameter.getPhoneNumber().matches(regex)){
//            throw new MindriveException("手机号格式错误");
//        }

        UserEntity user = new UserEntity();
        user.setId(id);
//        user.setUserId(parameter.getUserId());
        user.setUserName(parameter.getUserName());
        user.setIdNumber(parameter.getIdNumber());
        user.setBankCardNumber(parameter.getBankCardNumber());
//        user.setEmail(parameter.getEmail());
//        user.setPhoneNumber(parameter.getPhoneNumber());
        user.setUpdatedAt(new Date());
        user.setUpdator(loginUser.getUserId());
        userDao.updateById(user);
    }

    public void delete(List<String> ids) {
        userDao.removeByIds(ids);
    }

    public Map<String, Object> search(UsersSearchParameter parameter) {
        Map<String, Object> result = new HashMap<String, Object>();
        List<UserEntity> list = new ArrayList<UserEntity>();
        QueryWrapper<UserEntity> query = new QueryWrapper<UserEntity>();
        query.notIn("USER_ID", Arrays.asList(USER_ID_AUDIT, USER_ID_SECURITY, USER_ID_SYSTEM));
        if (parameter.getName() != null && !"".equals(parameter.getName())) {
//            query.and(wrapper -> wrapper.or().like("USER_ID", parameter.getName()).or()
//                    .like("USER_NAME", parameter.getName()));
            query.like("USER_NAME" , parameter.getName());
        }
        if (parameter.getUserId() != null && !"".equals(parameter.getUserId())) {
            query.like("USER_ID" , parameter.getUserId());
        }
        if (parameter.getPhoneNumber() != null && !"".equals(parameter.getPhoneNumber())) {
            query.like("PHONE_NUMBER" , parameter.getPhoneNumber());
        }
        if (parameter.getRoleName() != null && !"".equals(parameter.getRoleName())){
            QueryWrapper<RoleEntity> roleQuery = new QueryWrapper<>();
            roleQuery.like("NAME" , parameter.getRoleName());
            final List<RoleEntity> list1 = roleDao.list(roleQuery);
            if (list1.size() > 0){
                QueryWrapper<UserRoleEntity> userRoleQuery = new QueryWrapper<>();
                userRoleQuery.eq("ROLE_ID" , list1.get(0).getId());
                final List<UserRoleEntity> userRolelist = userRoleDao.list(userRoleQuery);
                List<String> userids = userRolelist.stream().map(UserRoleEntity::getUserId).collect(Collectors.toList());
                query.in("ID", userids);
            }else {
                result.put(COUNT, 0);
                result.put(LIST, list);
                return result;
            }

        }
        int count = userDao.count(query);
//        query.select("ID", "USER_ID", "USER_NAME", "EMAIL", "PHONE_NUMBER" , "AVATAR" , "STATUS");

        Page<UserEntity> page = page(UserEntity.class, parameter.getPageSize(), parameter.getCurrentPage());
        if (page == null) {
            list = userDao.list(query);
        } else {
            userDao.page(page, query);
            list = page.getRecords();
        }

        result.put(COUNT, count);
        result.put(LIST, list);
        return result;
    }

    public void modifyPassword(PasswordParameter parameter) {

        UserEntity loginUser = getLoginUser();
//        BCryptPasswordEncoder oldencoder = new BCryptPasswordEncoder();
//        String oldpwd = oldencoder.encode(parameter.getOldpassword());
        try {
            authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(loginUser.getUserId(), parameter.getOldpassword()));
        } catch (BadCredentialsException e) {
            // 密码错误
            throw new MindriveException("旧密码错误,请重新输入");
        }
//        if (!loginUser.getPassword().equals(oldpwd)){
//
//        }
        BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
        String pwd = encoder.encode(parameter.getNewpassword());
        UserEntity modify = new UserEntity();
        modify.setId(loginUser.getId());
        modify.setPassword(pwd);
        userDao.updateById(modify);

    }

    public void setAvatar(String id, MultipartFile file) {

        InputStream avatarInputStream = null;
        try {
            avatarInputStream = file.getInputStream();
            File useAvatar = new File(destPath + File.separator + USER_AVATAR + File.separator + id);
            FileUtils.copyInputStreamToFile(avatarInputStream, useAvatar);
            UserEntity update = new UserEntity();
            update.setId(id);
            update.setAvatar(id);
            userDao.updateById(update);

        } catch (IOException e) {
            log.error("保存头像失败", e);
        } finally {
            if (avatarInputStream != null) {
                try {
                    avatarInputStream.close();
                } catch (IOException e) {
                    avatarInputStream = null;
                }
            }
        }
    }

    public void getAvatar(HttpServletResponse response, String id) {
        log.debug(">>>>>>>取得用户头像。" + id);
        UserEntity expert = userDao.getById(id);

        String fileName = expert.getUserName();

        InputStream inputStream = null;
        try {
            File avatarFile = new File(destPath + File.separator + USER_AVATAR + File.separator + id);
            inputStream = new FileInputStream(avatarFile);
            ByteArrayOutputStream os = new ByteArrayOutputStream();
            int b = 0;
            while ((b = inputStream.read()) != -1) {
                os.write(b);
            }
            // 设置response返回头部信息
            response.setHeader("content-type", "image/png");
            response.setContentType("image/png");
            response.setHeader("Content-Disposition", "inline;filename=\"" + fileName + "\"");
            response.setHeader("X-Frame-Options", "SAMEORIGIN");
            response.setContentLength(os.size());
            response.getOutputStream().write(os.toByteArray());
        } catch (Exception ex) {
            log.error("取得用户头像.[{}]", id, ex);
        } finally {
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    inputStream = null;
                }
            }
        }
    }

    public void resetPassword(String id) {
        UserEntity user = userDao.getById(id);
        BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
        String pwd = encoder.encode(user.getUserId() + "123456");

        UserEntity modify = new UserEntity();
        modify.setId(id);
        modify.setPassword(pwd);
        userDao.updateById(modify);
    }

    public Map<String, Object> getLoginUserInfo() {
        Map<String, Object> result = new HashMap<String, Object>();

        UserEntity loginUser = getLoginUser();
        result.put("user", loginUser);
        QueryWrapper<UserRoleEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("USER_ID" , loginUser.getId());
        final List<UserRoleEntity> roles = userRoleDao.list(queryWrapper);
        String roleStr = "";
        int flat = 1;
        for (UserRoleEntity userRoleEntity : roles){
            final RoleEntity role = roleDao.getById(userRoleEntity.getRoleId());
            if (role != null){
                roleStr += role.getName();
                if (flat != roles.size()){
                    roleStr += ";";
                }
                flat++;
            }
        }
        result.put("role", roleStr);
        List<String> permissionIds = getCurrentUserPermissionList(loginUser);


        List<Map<String, Object>> menus = generateLoginUserMenus(loginUser, permissionIds);
        result.put("menus", menus);

        List<String> permissions = generateLoginUserPermissions(loginUser, permissionIds);
        result.put("permissions", permissions);

        return result;
    }

    public List<Map<String, Object>> generateLoginUserMenus(UserEntity loginUser, List<String> permissionIds) {
        List<Map<String, Object>> result = new ArrayList<Map<String, Object>>();
        if (permissionIds.size() == 0) {
            return result;
        }
        List<PermissionEntity> permissions = permissionDao.listByIds(permissionIds);
        for (PermissionEntity permission : permissions) {
            List<String> ancestors = permissionDao.getAncestors(permission.getId());
            permissionIds.addAll(ancestors);
        }

        List<PermissionEntity> permissionAll = permissionDao.search(permissionIds, "0");
        List<Map<String, Object>> menus = getUserMenuIterationVue(permissionAll, "", loginUser.getCurrentWorkspaceId());

        return menus;
    }

    public List<String> generateLoginUserPermissions(UserEntity loginUser, List<String> permissionIds) {

        final UserEntity user = userDao.getUserByUserId(loginUser.getUserId());
        List<String> permissions = new ArrayList<String>();
        if (permissionIds.size() == 0) {
            return permissions;
        }
        QueryWrapper<RoleEntity> roleQuery = new QueryWrapper<>();
        roleQuery.eq("PERSON_IN_CHANGE" , user.getId());
        final List<RoleEntity> list = roleDao.list(roleQuery);
        // 功能权限
        if (user.getUserId().equals(USER_ID_SYSTEM)){
//            permissions.add(ANNIUGONGNENG_XINZENG);
//            permissions.add(ANNIUGONGNENG_TIANBAO);
//            permissions.add(ANNIUGONGNENG_ZHUGUANSHENHE);
//            permissions.add(ANNIUGONGNENG_BIANJI);
            permissions.add(ANNIUGONGNENG_CAIWUSHENHE);
            permissions.add(ANNIUGONGNENG_XIAZAI);
            permissions.add(ANNIUGONGNENG_YINHANGBAOBIAO);

            permissions.add(ANNIUGONGNENG_RICHENGADD);
            permissions.add(ANNIUGONGNENG_RICHENGUPDATE);
        } else if (list.size() > 0){
            //主管人员
            permissions.add(ANNIUGONGNENG_XINZENG);
            permissions.add(ANNIUGONGNENG_ZHUGUANSHENHE);
            permissions.add(ANNIUGONGNENG_BIANJI);
            permissions.add(ANNIUGONGNENG_XIAZAI);
            permissions.add(ANNIUGONGNENG_TIANBAO);
            permissions.add(ANNIUGONGNENG_HANGSHANCHU);

            permissions.add(ANNIUGONGNENG_RICHENGADD);
            permissions.add(ANNIUGONGNENG_RICHENGUPDATE);
        }else {
            //普通用户
//            permissions.add(ANNIUGONGNENG_XINZENG);
            permissions.add(ANNIUGONGNENG_TIANBAO);
        }


        return permissions;

    }

    /**
     * 用户菜单迭代器
     *
     * @return
     */
    public List<Map<String, Object>> getUserMenuIterationVue(List<PermissionEntity> permissions, String parentId,
                                                          String workspaceId) {

        List<Map<String, Object>> menus = new ArrayList<Map<String, Object>>();
        for (PermissionEntity menu : permissions) {
            log.debug("menu:[{}]", JSON.toJSONString(menu));
            if (StringUtils.isBlank(menu.getParentId())){
                Map<String, Object> groupMenu = new HashMap<>();
                groupMenu.put("key" , menu.getId());
                groupMenu.put("path", menu.getRoute());
                groupMenu.put("title" , menu.getTitle());
                groupMenu.put("component", "@/views"+menu.getRoute()+"/index");

                List<Map<String, Object>> childrenMenu = getUserMenuErJi(permissions , menu.getId());
                groupMenu.put("children", childrenMenu);
                menus.add(groupMenu);
            }
        }
        return menus;
    }
    public List<Map<String, Object>> getUserMenuErJi(List<PermissionEntity> permissions , String parentId){
        List<Map<String, Object>> menus = new ArrayList<Map<String, Object>>();
        for (PermissionEntity per : permissions){
            if (per.getParentId().equals(parentId)){
                Map<String, Object> groupMenu = new HashMap<>();
                groupMenu.put("key" , per.getId());
                groupMenu.put("path", per.getRoute());
                groupMenu.put("title" , per.getTitle());
                groupMenu.put("component", "@/views"+per.getRoute()+"/index");
                menus.add(groupMenu);
            }
        }
        return menus;
    }


    /**
     * 用户菜单迭代器
     *
     * @return
     */
    public List<Map<String, Object>> getUserMenuIteration(List<PermissionEntity> permissions, String parentId,
            String workspaceId) {

        List<Map<String, Object>> menus = new ArrayList<Map<String, Object>>();
        for (PermissionEntity menu : permissions) {
            log.debug("menu:[{}]", JSON.toJSONString(menu));
            if (menu.getParentId().equals(parentId)) {
                Map<String, Object> item = new HashMap<String, Object>();
                item.put("title", menu.getTitle());
                Map<String, String> icon = new HashMap<String, String>();
                icon.put("path", "iconfont");
                icon.put("component", menu.getIcon());
                item.put("key", icon);

                List<Map<String, Object>> childrenMenu = getUserMenuIteration(permissions, menu.getId(), workspaceId);
                item.put("children", childrenMenu);
                item.put("link", menu.getRoute());
                menus.add(item);
            }

        }
        return menus;
    }


    public List<String> getCurrentUserPermissionList(UserEntity loginUser) {
        List<String> permissionIds = new ArrayList<String>();

        QueryWrapper<UserRoleEntity> query = new QueryWrapper<UserRoleEntity>();
        query.eq("user_id", loginUser.getId());
        List<UserRoleEntity> roles = userRoleDao.list(query);
        List<String> roleIds = roles.stream().map(item -> item.getRoleId()).collect(Collectors.toList());

        if (roleIds != null && roleIds.size() != 0) {
            for (String roleId : roleIds) {
                List<String> permissons = roleDao.getRolePermissions(roleId);
                permissionIds.addAll(permissons);
            }
        }
        return permissionIds;
    }


    public void active(List<String> userIds) {

        for (String userId : userIds) {
            UserEntity user = userDao.getById(userId);
            if (user.getStatus().equals(USER_STATUS_NORMAL)) {
                log.debug("成员已经启用，不需要再次启用。[{}]", userId);
            } else {
                try {
                    UserEntity update = new UserEntity();
                    update.setId(userId);
                    update.setStatus(USER_STATUS_NORMAL);
                    userDao.updateById(update);
                } catch (Exception ex) {
                    log.error("用户启用失败。[{}]", userId, ex);
                }

            }

        }

    }

    /**
     * 成员的停用
     */
    public void deactive(List<String> userIds) {

        for (String userId : userIds) {
            UserEntity employee = userDao.getById(userId);
            if (employee.getStatus().equals(USER_STATUS_REMOVED)) {
                log.debug("成员已经停用，不需要再次停用。[{}]", userId);
            } else {
                try {
                    UserEntity update = new UserEntity();
                    update.setId(userId);
                    update.setStatus(USER_STATUS_REMOVED);
                    userDao.updateById(update);
                } catch (Exception ex) {
                    log.error("用户停用失败。[{}]", userId, ex);
                }

            }

        }

    }

    public static Boolean convertToPinyin(String chinese) {
        char[] charArray = chinese.toCharArray();
        // 单个字的多个音组成的数组
        String[] multiPinYinArray;
        HanyuPinyinOutputFormat format = new HanyuPinyinOutputFormat();
        format.setCaseType(HanyuPinyinCaseType.LOWERCASE);
        format.setToneType(HanyuPinyinToneType.WITHOUT_TONE);
        format.setVCharType(HanyuPinyinVCharType.WITH_V);
        StringBuilder result = new StringBuilder();
        for (char c : charArray) {
            //判断是否为汉字字符
            if (Character.toString(c).matches("[\\u4E00-\\u9FA5]+")) {
                return true;
            }
        }
        return false;
    }

}
